package com.cz.ioc.container;

import com.cz.ioc.annotation.IComponent;
import com.cz.ioc.annotation.Inject;
import com.cz.ioc.util.IocScanner;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

/**
 * @version 1.0.0
 * @Description IOC容器
 */
public class MyIocContainer {


    private static Map<String, Object> beanMap = new HashMap<>();

    static {
        Properties properties = new Properties();
        // 使用ClassLoader加载properties配置文件生成对应的输入流
        InputStream in = MyIocContainer.class.getClassLoader().getResourceAsStream("myspring.properties");
        // 使用properties对象加载输入流
        try {
            properties.load(in);
        } catch (IOException e) {
            e.printStackTrace();
        }
        //获取key对应的value值
        String packages = properties.getProperty("packages");
        IocScanner iocScanner = new IocScanner();
        try {
            // 对所有component进行实例化，放进缓存
            Set<Class<?>> components = iocScanner.getAnnotationClasses(packages, IComponent.class);
            for (Class<?> component : components) {
                String name = component.getAnnotation(IComponent.class).value();
                beanMap.put(name, component.newInstance());
            }

            // 不考虑循环依赖，对他们的属性中有Inject注解的进行注入
            for (Class<?> component : components) {
                Field[] declaredFields = component.getDeclaredFields();
                String name = component.getAnnotation(IComponent.class).value();
                Object o = beanMap.get(name);
                for (Field field : declaredFields) {

                    if (field.isAnnotationPresent(Inject.class)) {
                        String fieldName = field.getAnnotation(Inject.class).value();
                        field.setAccessible(true);
                        field.set(o, beanMap.get(fieldName));
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    public <T> T getEntity(String name) {
        return (T) beanMap.get(name);
    }


}
